#!encoding: utf-8
import re

default_pyadmin = {
    'ip': '127.0.0.1',
    'port': 5000,
    'debug': False,
    'pid_file': '/var/run/pyadmin.pid',
    'log_file': '/var/log/pyadmin.log'
}

default_pyctl = {
    'py_ip': '127.0.0.1',
    'py_port': 5000
}

## 最初只提供必须字段
cfg_result = {
    'host': {
        'ip': [],
        'title': '',
        'desc': '',
        'maintainer': '',
        'pyadmin': {
            'ip': '',
            'port': 0
        },
        'procs': {}
    }
}

proc = {
    'start_command': '',
    'stop_command': '',
    'ps_str': ''
}

required_keys_of_root = ['host']

required_keys_of_host = ['ip', 'title', 'desc', 'maintainer', 'pyadmin', 'procs']
optional_keys_of_host = ['pyctl', 'groups']

required_keys_of_pyadmin = ['ip', 'port']
optional_keys_of_pyadmin = ['delay_time', 'debug', 'pid_file', 'log_file']

required_keys_of_proc = ['start_command', 'stop_command', 'ps_str']
optional_keys_of_proc = ['auto_restart']

class Validator():
    @classmethod
    def validate_ip(cls, ip):
        return re.match('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', ip)
    @classmethod
    def validate_host_ip(cls, ip_list):
        '''
        1. 必须是list类型
        2. 必须不能为空
        3. 列表成员格式必须正确
        '''
        cfg_result['host']['ip'] = []
        if not isinstance(ip_list, list):
            print('Invalid type of \'ip\', please use list')
            return False
        elif [] == ip_list:
            print('The ip field of host can\'t be empty')
            return False
        for ip in ip_list:
            ## 用正则验证ip
            if not cls.validate_ip(ip):
                return False
            else:
                cfg_result['host']['ip'].append(ip)
        return True
    @classmethod
    def validate_port(cls, port):
        try:
            port = int(port)
            return True
        except Exception, e:
            return False
    @classmethod
    def __validate_delay_time(cls):
        pass
    @classmethod
    def validate_debug(self, debug):
        return isinstance(debug, bool)
    @classmethod
    def __validate_host_title(self, title):
        if '' == title:
            print('Error: the title can\'t be empty')
            return False
        return True
    @classmethod
    def __validate_host_desc(self, desc):
        if '' == desc:
            print('Error: the desc can\'t be empty')
            return False
        return True
    @classmethod
    def __validate_host_maintainer(self, maintainer):
        if '' == maintainer:
            print('Error: the maintainer can\'t be empty')
            return False
        return True
    @classmethod
    def __validate_proc(cls, proc):
        '''
        1. 必须有启/停命令, 不可为空
        2. 必须有ps字符串, 不可为空
        '''
        if not isinstance(proc, dict):
            ## <???>这里需要注明proc名称
            print('Invalid type of \'proc\', please use proc')
            return False
        keys_of_proc = proc.keys()
        lost = list(set(required_keys_of_proc).difference(set(proc)))
        extra = list(set(proc).difference(set(required_keys_of_proc)))
        invalid = list(set(extra).difference(set(optional_keys_of_proc)))
        if not [] == lost:
            print('Lost keys: %s' % lost)
            return False
        elif not [] == invalid:
            print('Invalid keys: %s' % invalid)
            return False
        return True
    @classmethod
    def validate_procs(cls, procs):
        '''
        1. procs字段类型必须为dict
        2. 可为空, 若不为空则需要检测字段规则.
        '''
        if procs == {} or procs == None:
            return True

        for proc in procs.keys():
            if not cls.__validate_proc(procs[proc]):
                return False
        return True
    @classmethod
    def validate_group(cls, group):
        return True

    @classmethod
    def validate_main(cls, cfg):
        '''
        1. 根字段必须有也只能有host字段
        '''
        #######################################################################
        if not isinstance(cfg, dict):
            print('Invalid type of \'yml cfg\', please use dict')
            return None
        ## 与必选字段求差集, 必选字段不能少
        lost = list(set(cfg.keys()).difference(set(required_keys_of_root)))
        ## 多余字段需要在可选字段列表中, 不能是非法字段
        invalid = list(set(required_keys_of_root).difference(set(cfg.keys())))
        if not [] == lost:
            print('Lost keys: %s' % lost)
            return None
        elif not [] == invalid:
            print('Invalid keys: %s' % invalid)
            return None

        #######################################################################
        ## 这里暂时认为host字段下的键都是唯一的
        keys_of_host = cfg['host'].keys()
        lost = list(set(required_keys_of_host).difference(set(cfg['host'])))
        extra = list(set(cfg['host']).difference(set(required_keys_of_host)))
        invalid = list(set(extra).difference(set(optional_keys_of_host)))
        if not [] == lost:
            print('Lost keys: %s' % lost)
            return None
        elif not [] == invalid:
            print('Invalid keys: %s' % extra)
            return None
        ######################################################################
        ## 格式验证并赋值

        if not cls.validate_host_ip(cfg['host']['ip']):
            return None
        else:
            cfg_result['host']['ip'] = cfg['host']['ip']
        
        if not cls.__validate_host_title(cfg['host']['title']):
            return None
        else:
            cfg_result['host']['title'] = cfg['host']['title']

        if not cls.__validate_host_desc(cfg['host']['desc']):
            return None
        else:
            cfg_result['host']['desc'] = cfg['host']['desc']

        if not cls.__validate_host_maintainer(cfg['host']['maintainer']):
            return None
        else:
            cfg_result['host']['maintainer'] = cfg['host']['maintainer']

        if not cls.validate_pyadmin(cfg['host']['pyadmin']):
            return None
        else:
            cfg_result['host']['pyadmin'] = cfg['host']['pyadmin']
        
        if not cls.validate_procs(cfg['host']['procs']):
            return None
        elif cfg['host']['procs'] == None:
            cfg_result['host']['procs'] = {}
        else:
            cfg_result['host']['procs'] = cfg['host']['procs']

        ## if cfg['host'].has_key('pyctl'):

        if cfg['host'].has_key('groups'):
            if not cls.validate_group(cfg['host']['groups']):
                return None
            cfg_result['host']['groups'] = cfg['host']['groups']
        else:
            cfg_result['host']['groups'] = {}

        return cfg_result
    @classmethod
    def validate_pyadmin(cls, pyadmin):
        lost = list(set(required_keys_of_pyadmin).difference(set(pyadmin.keys())))
        extra = list(set(pyadmin.keys()).difference(set(required_keys_of_pyadmin)))
        invalid = list(set(extra).difference(set(optional_keys_of_pyadmin)))
        if not [] == lost:
            print('Lost keys: %s' % lost)
            return False
        elif not [] == invalid:
            print('Invalid keys: %s' % extra)
            return False
        
        if not cls.validate_ip(pyadmin['ip']):
            return False

        if not cls.validate_port(pyadmin['port']):
            return False

        if not pyadmin.has_key('debug'):
            pyadmin['debug'] = False
        elif not cls.validate_debug(pyadmin['debug']):
            return False
        
        return True
    @classmethod
    def validate_pyctl(cls):
        pass